﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

namespace FindFile
{
    public partial class FindFileForm : Form
    {
        public FindFileForm()
        {
            InitializeComponent();

            _displayNameGenerator = new NameAndPathDisplayNameGenerator();
        }

        public INameMatcher NameMatcher
        {
            get { return _nameMatcher; }
            set { _nameMatcher = value; }
        }
            
        #region Widget event handlers
        private void _txtSearch_KeyUp(object sender, KeyEventArgs e)
        {
            List<NameMatch> matches = _nameMatcher.Match(_txtSearch.Text);
            _lstboxHits.DataSource = matches;
        }

        void _lstboxHits_DrawItem(object sender, DrawItemEventArgs e)
        {
            NameMatch nameMatch;
            if (TryGetNameMatchAt(e.Index, out nameMatch))
            {
                e.DrawBackground();
                e.DrawFocusRectangle();
                this.DrawName(e, nameMatch);
                //this.DrawNameWithHighlightedMatches(e, nameMatch);
            }
        }

        private void DrawName(DrawItemEventArgs e, NameMatch nameMatch)
        {
            using (Brush textBrush = new SolidBrush(e.ForeColor))
            {
                e.Graphics.DrawString(nameMatch.Name, this.Font, textBrush, e.Bounds.Location);
            }
        }

        private void DrawNameWithHighlightedMatches(DrawItemEventArgs e, NameMatch nameMatch)
        {
            int index = 0;
            PointF charTopLeft = e.Bounds.Location;

            using (Brush textBrush = new SolidBrush(e.ForeColor))
            using (Font highlightFont = new Font(this.Font, FontStyle.Bold))
            {
                foreach (char c in nameMatch.Name)
                {
                    string charAsString = c.ToString();
                    Font font = nameMatch.MatchedCharacterIndices.Contains(index) ? highlightFont : this.Font;
                    e.Graphics.DrawString(charAsString, font, textBrush, charTopLeft);
                    charTopLeft.X += e.Graphics.MeasureString(charAsString, font).Width;
                    index++;
                }
            }
        }

        private bool TryGetNameMatchAt(int index, out NameMatch nameMatch)
        {
            if (index < 0 || index >= _lstboxHits.Items.Count)
            {
                nameMatch = null;
                return false;
            }
            nameMatch = (NameMatch)_lstboxHits.Items[index];
            return true;
        }

        private void _lstboxHits_KeyUp(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Return)
            {
                this.CloseThisWithOKResult();
            }
        }

        private void _lstboxHits_MouseDoubleClick(object sender, MouseEventArgs e)
        {
            this.CloseThisWithOKResult();
        }

        #endregion

        internal PhysicalFile ChosenPhysicalFile
        {
            get
            {
                NameMatch nameMatch;
                TryGetNameMatchAt(_lstboxHits.SelectedIndex, out nameMatch);
                return nameMatch.PhysicalFile;
            }
        }

        protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
        {
            // Jumping through some hoops so that the user
            // immediately can select with return, 
            // use down arrow to immediately start selecting in ListBox etc
            if (msg.Msg == WM_KEYDOWN)
            {
                if (keyData == Keys.Escape)
                {
                    base.DialogResult = DialogResult.Cancel;
                    base.Close();
                    return true;
                }
                if ((keyData == Keys.Down) && !_lstboxHits.Focused)
                {
                    int count = _lstboxHits.Items.Count;
                    if (count == 0)
                    {
                        return false;
                    }
                    if ((_lstboxHits.SelectedIndex >= 0) && (_lstboxHits.SelectedIndex < (count - 1)))
                    {
                        _lstboxHits.SelectedIndex++;
                        _lstboxHits.Focus();
                    }
                }
                if (keyData == Keys.Return)
                {
                    this.CloseThisWithOKResult();
                    return true;
                }
            }
            return base.ProcessCmdKey(ref msg, keyData);
        }

        private void CloseThisWithOKResult()
        {
            base.DialogResult = DialogResult.OK;
            base.Close();
        }

        const int WM_KEYDOWN = 0x100;
        readonly IDisplayNameGenerator _displayNameGenerator;
        INameMatcher _nameMatcher;

    }
}
